import { h, onMounted, onUnmounted, ref } from 'vue';
import { Pagination, Button } from 'ant-design-vue';
import { LoadingOutlined } from '@ant-design/icons-vue';
import CEmpty from '@gis/lib/components/CEmpty.vue';

const CList = {
  name: 'CList',
  props: {
    fetch: { type: Function, default: undefined },
    fetchParams: { type: Object, default: undefined },
    dataSource: { type: Array, default: undefined },
    immediate: { type: Boolean, default: undefined },
    rowKey: { type: String, default: 'id' },
    pagination: { type: [Object, Boolean], default: undefined },
    useLoadMore: { type: [Object, Boolean], default: undefined },
    loadingSize: { type: String, default: undefined },
    showEmpty: { type: Boolean, default: undefined },
  },
  setup(props, { attrs, slots, expose }) {
    let FETCH_PARAMS = {};
    let dataList = ref([]);
    let loading = ref(false);
    let finished = ref(true);
    let total = ref(0);
    let page = ref(1);
    let pageSize = ref(10);
    let STYLE = {
      flex: {
        display: 'flex',
        flexDirection: 'column',
        flexWrap: 'nowrap',
        justifyContent: 'flex-start',
        alignItems: 'flex-start',
        width: '100%',
        height: '100%',
      },
      autoHeight: {
        flex: 'auto',
        width: '100%',
        height: 'auto',
        minHeight: 0,
        overflow: 'hidden auto',
      },
      fixedStyle: { flex: 'none', width: '100%' },
      loadingStyle: {},
    };
    STYLE.loadingStyle = {
      ...STYLE.flex,
      justifyContent: 'center',
      alignItems: 'center',
      position: 'absolute',
      top: 0,
      left: 0,
      zIndex: 1,
      background: 'rgba(0,0,0,0.05)',
    };

    async function load(params) {
      if (loading.value) return;
      loading.value = true;
      if (typeof props.fetch === 'function') {
        let fetchParams = props.fetchParams;
        if (typeof props.fetchParams === 'function') {
          fetchParams = props.fetchParams();
        }
        FETCH_PARAMS = Object.assign({}, FETCH_PARAMS, fetchParams, params, {
          page_size: pageSize.value,
          page_number: page.value,
        });
        let res = null;
        try {
          res = (await props.fetch(Object.assign({}, FETCH_PARAMS))) || {};
        } catch (e) {
          res = { data: [], total: 0 };
        }
        if (!Array.isArray(res.data)) {
          res.data = [];
        }
        if (!Number.isFinite(res.total)) {
          res.total = 0;
        }
        if (FETCH_PARAMS === null) {
          /* 组件已销毁 */
          return;
        }
        if (props.useLoadMore === true) {
          dataList.value = [].concat(dataList.value, res.data);
        } else {
          dataList.value = res.data;
        }
        total.value = res.total;
        finished.value = res.data.length < pageSize.value;
      } else if (Array.isArray(props.dataSource)) {
        let cur = page.value - 1;
        if (cur >= 0) {
          let data = props.dataSource.slice(cur * pageSize.value, page.value * pageSize.value);
          if (props.useLoadMore === true) {
            dataList.value = [].concat(dataList.value, data);
          } else {
            dataList.value = data;
          }
          finished.value = data.length < pageSize.value;
        }
        total.value = props.dataSource.length;
      }
      loading.value = false;
    }
    async function reload(params) {
      page.value = 1;
      await load(params);
    }

    let renderLoading = () => {
      let iconStyle = { fontSize: props.loadingSize || '30px' };
      return h('div', { style: STYLE.loadingStyle }, h(LoadingOutlined, { style: iconStyle }));
    };
    let renderEmpty = () => {
      return loading.value ? null : h(slots.empty ? slots.empty : CEmpty);
    };
    let renderItemSlot = () => {
      return dataList.value.length
        ? dataList.value.map((item) =>
            h(slots.item, { key: item[props.rowKey], scope: item, dataList: dataList.value })
          )
        : renderEmpty();
    };
    let renderDefaultSlot = () => {
      return h(slots.default, {
        dataList: dataList.value,
        pagination: { pageSize: pageSize.value, current: page.value, total: total.value },
      });
    };
    if (props.showEmpty === true) {
      renderDefaultSlot = () => {
        return dataList.value.length ? h(slots.default, { dataList: dataList.value }) : renderEmpty();
      };
    }
    let renderLoadMoreBtn = () => {
      if (props.useLoadMore !== true) {
        return null;
      }
      let dftProps = {
        style: { margin: '0.8em 0 0' },
        loading: loading.value,
        onClick: () => {
          page.value += 1;
          load();
        },
      };
      return h('div', { style: { ...STYLE.fixedStyle, textAlign: 'center' } }, [
        finished.value ? null : h(Button, dftProps, '加载更多'),
        // h(Button, dftProps, '加载更多'),
      ]);
    };
    let renderPagination = () => {
      if (props.pagination === false || props.pagination === null) {
        return null;
      }
      let dftProps = {
        style: { padding: '0.8em 0 0' },
        hideOnSinglePage: true,
        showSizeChanger: true,
        showQuickJumper: true,
        showTotal: (total) => '共 ' + total + ' 条',
      };
      return h('div', { style: { ...STYLE.fixedStyle, textAlign: 'right' } }, [
        h(
          Pagination,
          Object.assign(dftProps, props.pagination, {
            current: page.value,
            pageSize: pageSize.value,
            total: total.value,
            onChange: (current) => {
              page.value = current;
              load();
            },
          })
        ),
      ]);
    };

    onMounted(() => {
      if (props.immediate === true) {
        load();
      }
    });
    onUnmounted(() => {
      props = attrs = slots = FETCH_PARAMS = dataList = loading = total = page = pageSize = STYLE = null;
    });

    expose({ load, reload });

    return () => {
      return h('div', { style: STYLE.flex }, [
        h('div', { style: { ...STYLE.autoHeight, position: 'relative' } }, [
          slots.default ? renderDefaultSlot() : slots.item ? renderItemSlot() : null,
          loading.value ? renderLoading() : null,
        ]),
        renderLoadMoreBtn() || renderPagination(),
      ]);
    };
  },
};

export default CList;
